package model.Shapes 
{
	import fl.motion.MatrixTransformer;
	import flash.geom.Matrix;
	import model.ArrayBuilder;
	import model.observer.IModel;
	import model.observer.IView;
	import model.Point;
	import model.TetrisGame;
	
	/**
	 * ...
	 * @author Yang Wang
	 */
	public class TetrisShape implements IModel
	{
		private var m_views:Array;
		
		protected var m_orientation: int;
		protected var m_states:Array;
		protected var m_skirt:Array;
		protected var m_color:uint;
		protected var m_blockingPoints:Array;
		
		public function TetrisShape() {
			m_views = new Array();
		}
		
		public function rotateLeft() : void
		{
			m_orientation = getOrientationLeft();
			notifyViews();
		}
		
		public function rotateRight() : void
		{
			m_orientation = this.getOrientationRight();
			notifyViews();
		}
		
		
		public function get skirt() : Array {
			var skirt:Array = new Array();
			
			outerLoop: for (var x:int = 0; x < this.squares.length; x++)
			{
				for (var y:int = 0; y < (this.squares[x] as Array).length; y++)
				{
					if (squares[x][y] == true)
					{
						skirt[x] = y;
						continue outerLoop;
					}
				}
			}
			
			return skirt;
		}
		
		public function get squares() : Array {
			return m_states[m_orientation];
		}
		
		public function hasSquareAt(row:int, col:int) : Boolean {
			return m_states[m_orientation][row][col] != null;
		}
		
		/* INTERFACE model.observer.IModel */
		
		public function addView(view:IView):void 
		{
			this.m_views.push(view);
		}
		
		public function removeView(view:IView):void 
		{
			m_views.splice(m_views.indexOf(view), 1);
		}
		
		public function notifyViews() : void {
			for (var i:int = 0; i < m_views.length; i++) {
				var view :IView = m_views[i] as IView;
				view.updateView(new Object());
			}
		}
		
		public function get NumStates() : uint {
			return m_states.length;
		}
		
		public function get Orientation() : uint {
			return m_orientation;
		}
		
		public function getSquares(orientation:uint) : Array {
			return this.m_states[orientation];
		}
		
		public function get width() : uint {
			return (this.m_states[Orientation] as Array).length;
		}
		
		public function get height() : uint {
			return ((this.m_states[Orientation] as Array)[0] as Array).length;
		}
		
		public function get color():uint 
		{
			return m_color;
		}
		
		public function getOrientationLeft() : int {
			return (m_orientation + 1) % m_states.length;
		}
		
		public function getOrientationRight() : int {
			var o:int = m_orientation-1;
			if (o < 0) o+= m_states.length;
			return o % m_states.length;
		}
		
		public function equals(obj:Object) : Boolean {
			if (typeof(obj) == typeof(this)) {
				var shape:TetrisShape = obj as TetrisShape;
				if (shape.Orientation == this.Orientation) {
					return true;
				}
			}
			return false;
		}
		
		public function resetOrientation() : void{
			this.m_orientation = 0;
		}
		
		protected function rotatePoints(grid:Array, pivot:Point, counterclockwise:Boolean = true) : Array
		{
			var result:Array = new ArrayBuilder().build2DArray(grid.length, (grid[0] as Array).length);
			var rotation:int = 90;
			if (counterclockwise) rotation = 270;
			var matrix:Matrix = new Matrix();
			MatrixTransformer.rotateAroundInternalPoint(matrix, pivot.X, pivot.Y, rotation);
			
			
			for (var x:int = 0 ; x < grid.length; x++) {
				for (var y:int = 0; y < grid.length; y++) {
					if (grid[x][y] != null)
					{
						var geomPoint:flash.geom.Point = null;
						geomPoint = matrix.transformPoint(new flash.geom.Point(x, y));
						result[Math.round(geomPoint.x)][Math.round(geomPoint.y)] = grid[x][y];
					}
				}
			}
			return result;
		}
	}
	
}